#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "iobot.h"
#include "turtle.h"
#include "syscall.h"

iobot_t* cmdbot;
iobot_t* dirbot;
iobot_t* infobot;
char* input;
char* command;
char* param;
char history[128][1024];
char* working_dir;
int timeout = 300;
unsigned int history_pos = 0;
unsigned int history_view_pos = 0;
unsigned int input_pos = 0;
char code[8];
unsigned int years, months, days, hours, minutes, seconds = 0;

void update_dirbot()
{
	unsigned int res1, res2, res3, success = 0;
	unsigned int n = 0;
	char* name = (char*)malloc(sizeof(char) * 1024);

	iobot_clear_output(dirbot);
	dirbot->csr_x = 1; dirbot->csr_y = 1;
	iobot_put_string(dirbot, working_dir);
	iobot_put_string(dirbot, "\n  ");
	syscall3(SYS_READDIR, working_dir, n, name, res1, res2, res3, success)
	while(success)
	{
		iobot_put_string(dirbot, name);
		iobot_put_string(dirbot, "\n  ");
		n++;
		syscall3(SYS_READDIR, working_dir, n, name, res1, res2, res3, success)
	}
}

void update_infobot()
{
	unsigned int res1, res2, res3, res4, success = 0;	
	syscall4(SYS_TIME_INFO, 0, 0, 0, 0, res1, res2, res3, res4, success)
	years = res1 & 0x0000FFFF; months = res1 >> 16;
	days = res2 & 0x0000FFFF; hours = res2 >> 16;
	minutes = res3 & 0x0000FFFF; seconds = res3 >> 16;

	iobot_clear_output(infobot);
	infobot->csr_x = 1;
	infobot->csr_y = 1;

	iobot_put_number(infobot, days);
	iobot_put_string(infobot, "/");
	iobot_put_number(infobot, months);
	iobot_put_string(infobot, "/");
	iobot_put_number(infobot, years);
	iobot_put_string(infobot, " at ");
	iobot_put_number(infobot, hours);
	iobot_put_string(infobot, ":");
	iobot_put_number(infobot, minutes);
	iobot_put_string(infobot, ":");
	iobot_put_number(infobot, seconds);

	syscall2(SYS_MEM_INFO, 0, 0, res1, res2, success)

	iobot_put_string(infobot, "\n\n Total Memory: ");
	iobot_put_number(infobot, res1 / 1024);
	iobot_put_string(infobot, " kb\n");

	iobot_put_string(infobot, " Used:  ");
	iobot_put_number(infobot, res2 / 1024);
	iobot_put_string(infobot, " kb (");
	iobot_put_number(infobot, (res2 * 100) / res1);
	iobot_put_string(infobot, "%)\n");

	iobot_put_string(infobot, " Free:  ");
	iobot_put_number(infobot, (res1 - res2) / 1024);
	iobot_put_string(infobot, " kb (");
	iobot_put_number(infobot, 100 - ((res2 * 100) / res1));
	iobot_put_string(infobot, "%)\n");

	syscall1(SYS_CPU_INFO, 0, res1, success)

	iobot_put_string(infobot, " CPU Usage: ");
	iobot_put_number(infobot, res1);
	iobot_put_string(infobot, "%");
	
}

void parse_input(char* input, char* command, char* param)
{
	char* tmp;
	int token = 0;

	tmp = strtok(input," ");
	while (tmp != NULL)
	{
		if(token == 0)
		{
			strcpy(command, tmp);
		}
		else if(token == 1)
		{
			strcpy(param, tmp);
		}
		tmp = strtok(NULL, " ");
		token++;
	}
}

void update_history(char* input)
{
	if(history_pos > 127)
	{
		int si = 1; int di = 0;
		for(si = 1; si < 128; si++)
		{
			di = si - 1;
			memcpy(history[di], history[si], 1024);
		}
		history_pos = 127;
	}
	memcpy(history[history_pos], input, 1024);
	history_pos++;
	history_view_pos = history_pos;
}

void test_scroll(iobot_t* bot, int numlines)
{
	if((int)(bot->scroll + numlines) < 0)
		return;
	if((bot->scroll < (12288 / bot->textwidth)))
	{
		bot->scroll += numlines;
		bot->dirty_x = 1;
		bot->dirty_y = 1;
		bot->dirty_width = bot->textwidth + 1;
		bot->dirty_height = bot->textheight + 1;
		bot->dirty = 1;
	}
}

void handle_escape_code(char* code)
{
	if(strcmp(code,"ALF") == 0)
	{//left arrow
		if(input_pos > 0)
		{
			input_pos -= 1;
			cmdbot->csr_x -= 1;
		}
	}
	if(strcmp(code,"ART") == 0)
	{//right arrow
		if(input_pos < strlen(input))
		{
			input_pos += 1;
			cmdbot->csr_x += 1;
		}
	}
	if(strcmp(code,"HMK") == 0)
	{//home key
		cmdbot->csr_x -= input_pos;
		input_pos = 0;
	}
	if(strcmp(code,"ENK") == 0)
	{//end key
		cmdbot->csr_x += strlen(input) - input_pos;
		input_pos = strlen(input);
	}
	if(strcmp(code,"DEL") == 0)
	{//delete key
		int input_len = strlen(input);
		char* tmp = malloc(input_len);
		memset(tmp, 0, input_len);
		strncpy(tmp, input, input_pos);
		strcat(tmp, input + input_pos + 1);
		memset(input, 0, input_len);
		strncpy(input, tmp, strlen(tmp));
		free(tmp);
		iobot_delete(cmdbot);
	}
	if(strcmp(code,"AUP") == 0)
	{
		if(history_view_pos > 0)
		{
			cmdbot->csr_x = strlen(input) + 3;
			int i;
			for(i = strlen(input); i > 0; i--)
			{
				cmdbot->csr_x--;
				iobot_delete(cmdbot);
			}
			history_view_pos--;
			memcpy(input, history[history_view_pos], 1024);
			input_pos = strlen(input);
			iobot_put_string(cmdbot, input);
		}
	}
	if(strcmp(code,"ADN") == 0)
	{
		if(history_view_pos < history_pos)
		{
			cmdbot->csr_x = strlen(input) + 3;
			int i;
			for(i = strlen(input); i > 0; i--)
			{
				cmdbot->csr_x--;
				iobot_delete(cmdbot);
			}
			history_view_pos++;
			memcpy(input, history[history_view_pos], 1024);
			input_pos = strlen(input);
			iobot_put_string(cmdbot, input);
		}
	}
	if(strcmp(code,"PUP") == 0)
	{
		iobot_scroll(cmdbot, -2);
	}
	if(strcmp(code,"PDN") == 0)
	{
		iobot_scroll(cmdbot, 2);
	}

	cmdbot->dirty = 1;
	iobot_update_output(cmdbot);
}

int main()
{
	unsigned int res1, res2, res3, res4, success = 0;	

	turtle_create();

	memset(working_dir, 0, sizeof(char) * 1024);
	working_dir[0] = '/';

	iobot_put_string(cmdbot,"\nWelcome to Turtle Shell.\n\n"                     );	
	iobot_put_string(cmdbot,  "Fluidium Copyright (C) 2008 Stephen Dunn\n"       );
   iobot_put_string(cmdbot,  "This program comes with ABSOLUTELY NO WARRANTY.\n");
	iobot_put_string(cmdbot,  "This is free software, and you are welcome to\n"  );
	iobot_put_string(cmdbot,  "redistribute it under certain conditions.\n"      );
	iobot_put_string(cmdbot,  "See the file, 'gpl-3.0.txt' for details.\n"       );
	iobot_put_string(cmdbot,"\nType `help' to learn how to use Turtle Shell.\n"  );

	iobot_update_output(dirbot);
	iobot_update_output(cmdbot);
	iobot_update_output(infobot);

	char done = 0;	char enter = 0;
	while(done == 0)
	{
		iobot_put_string(cmdbot,"\n > ");
		update_dirbot();

		memset(input, 0, 1024);
		input_pos = 0;
		memset(command, 0, 1024);
		memset(param, 0, 1024);
		
		unsigned char temp = 0;
		enter = 0;
		while(!enter)
		{
			iobot_update_input(cmdbot);
			temp = iobot_get_char(cmdbot);
			while(temp)
			{
				switch(temp)
				{
					case '\n':
						enter = 1;
						temp = 0;
						break;
					case '\b':
						if(input_pos > 0)
						{
							input_pos--;
							cmdbot->csr_x--;
							handle_escape_code("DEL");
						}
						break;
					case '\020':/* -> */ ; /* <- "work-around" for "error: a label can only be part of a statement and a declaration is not a statement" */
						//some sort of escape code. Grab the three characters out of the input buffer.
						char code[4];
						code[0] = iobot_get_char(cmdbot);
						code[1] = iobot_get_char(cmdbot);
						code[2] = iobot_get_char(cmdbot);
						code[3] = 0;
						handle_escape_code(code);
						break;
					default:
						if(input_pos < 1024)
						{
							input[input_pos] = temp;
							input_pos++;
							iobot_put_char(cmdbot, temp);
						}
						break;
				}
				if(!enter)
				{
					temp = iobot_get_char(cmdbot);
				}
			}
			update_infobot();
			iobot_update_output(cmdbot);
			iobot_update_output(dirbot);
			iobot_update_output(infobot);
			syscall1(SYS_SLEEP, 2, res1, success)
		}

		update_history(input);
		parse_input(input, command, param);

		if(strcmp(command,"help") == 0)
		{
			unsigned int file = 0;
			syscall1(SYS_OPEN, "/packages/turtle/help.txt", file, success)
			if(success)
			{
				char* buffer = (char*)malloc(sizeof(char) * 1024);
				iobot_put_string(cmdbot,"\n\n");
				syscall4(SYS_READ, file, 0, buffer, 1024, res1, res2, res3, res4, success);
				buffer[1023] = 0x00;
				if(success)
					iobot_put_string(cmdbot, buffer);
				else
					iobot_put_string(cmdbot,"\nFailed to read the help file!\n");
				free(buffer);
				syscall1(SYS_CLOSE, file, res1, success)
			}
			else
			{
				iobot_put_string(cmdbot,"\nFailed to open the help file!\n");
			}
		} 
		else if(strcmp(command,"cd") == 0)
		{
			char* path = (char*)malloc(sizeof(char) * 1024);
			syscall3(SYS_FINDDIR, working_dir, param, path, res1, res2, res3, success)
			if(success)
			{
				strcpy(working_dir, path);
			}
			else
			{
				iobot_put_string(cmdbot,"\nCould not find that exact path.\n");
			}
			free(path);
		}
		else if(strcmp(command,"clear") == 0)
		{
			iobot_clear_output(cmdbot);
		} 
		else if(strcmp(command,"beep") == 0)
		{
			//TODO: Implement properly with a sound device
		} 
		else if(strcmp(command,"reboot") == 0)
		{
			syscall1(SYS_POWER_STATE, 0x01, res1, success)
		} 
		else if(strcmp(command,"shutdown") == 0)
		{
			syscall1(SYS_POWER_STATE, 0x02, res1, success)
		} 
		else if(strcmp(command,"disp") == 0)
		{
			if(strcmp(param,"left") == 0)
			{
				cmdbot->x = 0; cmdbot->y = 0;
				dirbot->x = 50; dirbot->y = 0;
				infobot->x = 50; infobot->y = 51;
			}
			else if(strcmp(param,"right") == 0)
			{
				cmdbot->x = 30; cmdbot->y = 0;
				dirbot->x = 0; dirbot->y = 0;
				infobot->x = 0; infobot->y = 51;
			}
			dirbot->dirty = 1; iobot_update_output(dirbot);
			infobot->dirty = 1; iobot_update_output(infobot);
			cmdbot->dirty_x = 0; cmdbot->dirty_y = 0;
			cmdbot->dirty_width = cmdbot->width;
			cmdbot->dirty_height = cmdbot->height;
			cmdbot->dirty = 1; iobot_update_output(cmdbot);
		}
		else if(strcmp(command,"usemem") == 0)
		{
			iobot_put_string(cmdbot,"\nmalloc(0x40000)...");
			unsigned int* tmp = malloc(0x40000);
			if(tmp)
			{
				tmp[0] = 0x01234567;
				tmp[0xFFFF] = 0x01234567;
				iobot_put_string(cmdbot,"success.\n");
			}
			else
			{
				iobot_put_string(cmdbot,"failed.\n");
			}
		}
		else if(strcmp(command,"peek") == 0)
		{
			unsigned int file = 0;
			char* full_name = (char*)malloc(sizeof(char) * 1024);

			syscall3(SYS_FINDDIR, working_dir, param, full_name, res1, res2, res3, success)
			if(success)
			{
				syscall1(SYS_OPEN, full_name, file, success)
				if(success)
				{
					char* buffer = (char*)malloc(sizeof(char) * 513);
					iobot_put_string(cmdbot,"\n\n");
					syscall4(SYS_READ, file, 0, buffer, 512, res1, res2, res3, res4, success);
					buffer[512] = 0x00;
					iobot_put_string(cmdbot, buffer);
					free(buffer);
					syscall1(SYS_CLOSE, file, res1, success)
				}
				else
				{
					iobot_put_string(cmdbot,"\nFailed to open '");
					iobot_put_string(cmdbot, full_name);
					iobot_put_string(cmdbot,"'\n");
				}
			}
			else
			{
				iobot_put_string(cmdbot,"\nFailed to find '");
				iobot_put_string(cmdbot, full_name);
				iobot_put_string(cmdbot,"'\n");
			}
			free(full_name);
		}
		else
		{
			//iobot_put_string(cmdbot,"\nInvalid command '");
			//iobot_put_string(cmdbot, command);
			//iobot_put_string(cmdbot,"'\n Type 'help' for more information.\n");

			iobot_put_string(cmdbot,"\nInvalid command.\nTrying path '");
			iobot_put_string(cmdbot, command);
			iobot_put_string(cmdbot,"'...");
			iobot_update_output(cmdbot);
			syscall1(SYS_EXEC, command, res1, success)
			if(!success)
			{
				iobot_put_string(cmdbot," Failed");
			}
			iobot_put_string(cmdbot, "\n");
		}
	}

	turtle_destroy();
	exit(0);
	return 1;
}

